package com.kongyz.demo.threadtest;

import java.util.concurrent.*;

/**
 * 信号量示例：允许多个线程同时访问
 * Synchronized 和 ReentrantLock 都是一次只允许一个线程访问某个资源，Semaphore(信号量) 可以指定多个线程同时访问某个资源
 *
 * @author kongyz
 */
public class SemaphoreExample {

    /**
     * 定义请求数量
     */
    private static final int THREAD_COUNT = 500;
    private static final int CORE_POOL_SIZE = 300;
    private static final int MAX_POOL_SIZE = 300;
    private static final int QUEUE_CAPACITY = 100;
    private static final Long KEEP_ALIVE_TIME = 0L;

    public static void main(String[] args) {
        //创建一个具有固定线程数量的线程池对象，（如果这里线程池的数量给的太少的话，你会发现执行的很慢）
        ExecutorService threadpool = new ThreadPoolExecutor(CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.MINUTES,
                new LinkedBlockingQueue<>(),
                new ThreadPoolExecutor.CallerRunsPolicy());
        //定义一次只能允许执行的线程数量
        final Semaphore semaphore = new Semaphore(20);

        for (int i = 0; i < THREAD_COUNT; i++) {
            final int threadNum = i;
            threadpool.execute(() -> {
                try {
                    //获取一个许可，所以可运行线程数量为20/1=20
                    semaphore.acquire(1);
                    test(threadNum);
                    //释放一个许可
                    semaphore.release(1);

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        threadpool.shutdown();
        System.out.println("完成");
    }

    private static void test(int threadNum) throws InterruptedException {
        //模拟请求耗时操作
        Thread.sleep(1000);
        System.out.println("当前线程数 threadNum:" + threadNum);
        Thread.sleep(1000);
    }


}
